﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
using System.Threading;
using LogLib;
using IPCPhotoEditor.Common;
using KAImage;
using KAImage.Config;

namespace IPCPhotoEditor
{

    public partial class CurveControl : UserControl
    {
        /// <summary>
        /// 标签是否为左键
        /// </summary>
        private bool leftFlag;

        private Pen linePen = new Pen(Color.Black, 2);

        private Pen pointPen = new Pen(Color.Black, 3);

        private CurvePointAction NewestAction = CurvePointAction.None;

        /// <summary>
        /// 整个图层的宽度
        /// </summary>
        private readonly int W = 510;

        /// <summary>
        /// 整个图层的高度
        /// </summary>
        private readonly int H = 510;

        public Spline[] splines = new Spline[4];

        public Spline TheSpline
        {
            get
            { 
                return splines[nColorChannel];
            }
        }

        public int[] Mapping
        {
            get 
            {
                if (nColorChannel >= 0 && nColorChannel < 4)
                {
                    return splines[nColorChannel].Mapping;
                }
                else
                {
                    throw new InvalidOperationException("参数无效");
                }
            }
        }

        public CurveUpdatedEventHandler CurveUpdated = null;
        protected void OnCurveUpdated()
        {
            if (CurveUpdated != null)
            {
                CurveUpdated(this, new CurveUpdatedEventArgs());
            }
        }

        /// <summary>
        /// 颜色通道
        /// </summary>
        private int nColorChannel = 0;
        public int ColorChannel
        {
            get { return nColorChannel; }
            set { nColorChannel = value; }
        }

        private QueueTaskManager _taskManager = new QueueTaskManager();    
      
        public void ResetPoints()
        {
            for (int i = 0; i < Mapping.Length;i++ )
            {
                Mapping[i] = i;
            }
           
            this.Invalidate();
        }

        public CurveControl()
        {
            CreatSplines();
            InitializeComponent();
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);       
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.UpdateStyles();
            ResetPoints();
        }

        private void CreatSplines()
        {
            splines[0] = new Spline();
            splines[1] = new Spline();
            splines[2] = new Spline();
            splines[3] = new Spline();

            splines[0].FrontColor = Color.Black;
            splines[1].FrontColor = Color.Red;
            splines[2].FrontColor = Color.Green;
            splines[3].FrontColor = Color.Blue;

            splines[0].ColorBrush = Brushes.Black;
            splines[1].ColorBrush = Brushes.Red;
            splines[2].ColorBrush = Brushes.Green;
            splines[3].ColorBrush = Brushes.Blue;
        }

        public MouseLocationReportedEventHandler MouseLocReported = null;

        private void OnMouseLocationUpdated(Point p)
        {
            if (MouseLocReported != null)
            {
                MouseLocReported(this, new MouseLocationReportedEventArgs(p));
            }
        }

        public void ApplySettings(ImageCurveOption option)
        {
            splines[0].Reset(option.General.ControlPoints);
            splines[1].Reset(option.Red.ControlPoints);
            splines[2].Reset(option.Green.ControlPoints);
            splines[3].Reset(option.Blue.ControlPoints);

            splines[0].FrontColor = Color.Black;
            splines[1].FrontColor = Color.Red;
            splines[2].FrontColor = Color.Green;
            splines[3].FrontColor = Color.Blue;

            splines[0].ColorBrush = Brushes.Black;
            splines[1].ColorBrush = Brushes.Red;
            splines[2].ColorBrush = Brushes.Green;
            splines[3].ColorBrush = Brushes.Blue;
        }

        private void DrawPoint(Graphics g)
        {
            pointPen.Color = TheSpline.FrontColor;
            for (int i = 0; i < TheSpline.OriginalDrawPoints.Count; i++)
            {
                Point p = TheSpline.OriginalDrawPoints[i];
                if (i == TheSpline.FocusIndex)
                {
                    g.FillRectangle(TheSpline.ColorBrush, p.X - 5, p.Y - 5, 10, 10);
                }
                else
                {
                    g.DrawRectangle(pointPen, p.X - 5, p.Y - 5, 10, 10);
                }
            }         
        }

        private void DrawDefaultCurve(Graphics g)
        {
            linePen.Color = TheSpline.FrontColor;
            pointPen.Color = TheSpline.FrontColor;
            g.DrawRectangle(pointPen, - 6, H - 6, 12, 12);
            g.DrawRectangle(pointPen, W - 6, - 6, 12, 12);
            g.DrawLine(linePen, 0, W - 2, H - 2, 0);     
        }

        private void DrawCurve(Graphics g)
        {
            linePen.Color = TheSpline.FrontColor;
            pointPen.Color = TheSpline.FrontColor;
            SmoothingMode oldMode = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.DrawLines(linePen, TheSpline.ListDrawingPoints.ToArray());
            g.SmoothingMode = oldMode;
        }

        private void CurveControl_Paint(object sender, PaintEventArgs e)
        {
            if (TheSpline.ListDrawingPoints.Count == 0)
            {
                DrawDefaultCurve(e.Graphics);     
            }
            else
            {
                DrawPoint(e.Graphics);
                DrawCurve(e.Graphics);     
            }
        }

        private void CurveControl_MouseUp(object sender, MouseEventArgs e)
        {
            if (leftFlag)
            {
                leftFlag = false;//释放鼠标后标注为false;
            }
        }

        private void CurveControl_MouseEnter(object sender, EventArgs e)
        {
            //_bFocused = true;
        }

        private void CurveControl_MouseLeave(object sender, EventArgs e)
        {
            //_bFocused = false;
        }

        public void SetCurvePointAction(Point p, CurvePointAction action)
        {
            CurvesAction task = new CurvesAction(this, p, action);
            _taskManager.AddTask(task);
        }

        /// <summary>
        /// 当鼠标拖动但没有操作关键点时
        /// </summary>
        private void WhenDragAnNotControlPoint(Point p)
        {
            CurvePointAction action = TheSpline.CalculateCurvePointAction(p);
            switch (action)
            {
                case CurvePointAction.Add:
                    this.Cursor = Cursors.Cross;
                    break;
                case CurvePointAction.Update:
                    this.Cursor = Cursors.SizeAll;
                    break;
                default:
                    this.Cursor = Cursors.Default;
                    break;
            }
        }

        private void CurveControl_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = e.Location;
            int x = p.X / 2;
            int y = (H - p.Y) / 2;
            Point np = new Point(x, y);            
            if (leftFlag)
            {
                OnMouseLocationUpdated(np);
                switch (NewestAction)
                {
                    case CurvePointAction.None:
                        WhenDragAnNotControlPoint(np);
                        break;
                    case CurvePointAction.Add:
                    case CurvePointAction.Update:
                        this.Cursor = Cursors.SizeAll;
                        SetCurvePointAction(np, CurvePointAction.Update);
                        break;
                    default:
                        break;
                }
            }
            else
            {
                if (TheSpline.FocusIndex < 0)
                {
                    OnMouseLocationUpdated(np);
                }
                WhenDragAnNotControlPoint(np);
            }           
        }

        private void CurveControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (!leftFlag)
            {
                // 按下鼠标后标注为true;
                leftFlag = true;
            }
            Point p = e.Location;
            int x = p.X / 2;
            int y = (H - p.Y) / 2;
            Point np = new Point(x, y);
            OnMouseLocationUpdated(np);
            NewestAction = TheSpline.CalculateCurvePointAction(np);
            SetCurvePointAction(np, NewestAction);
            switch (NewestAction)
            {
                case CurvePointAction.None:
                    this.Cursor = Cursors.Default;
                    break;
                case CurvePointAction.Clear:
                    this.Cursor = Cursors.Default;
                    break;
                case CurvePointAction.Add:
                    this.Cursor = Cursors.Cross;
                    break;
                case CurvePointAction.Remove:
                    break;
                case CurvePointAction.Update:
                    this.Cursor = Cursors.SizeAll;
                    break;
                default:
                    break;
            }           
        }

        private void CurveControl_Load(object sender, EventArgs e)
        {
            _taskManager.Context = SynchronizationContext.Current;         
            _taskManager.StartWorking();
        }

        public void StopBackgroudWorking()
        {
            _taskManager.Stop(3000);
        }

        private void CurveControl_KeyDown(object sender, KeyEventArgs e)
        {
            if (TheSpline.IsEmpty || TheSpline.FocusIndex < 0)
            {
                return;
            }
            if (e.KeyData == Keys.Delete)
            {
                SetCurvePointAction(new Point(0, 0), CurvePointAction.Remove);
            }
        }

        public ImageCurveOption CreatConfigOption()
        {
            ImageCurveOption option = new ImageCurveOption();
            option.General.SetControlPoints(splines[0].OriginalPoints);
            option.Red.SetControlPoints(splines[1].OriginalPoints);
            option.Green.SetControlPoints(splines[2].OriginalPoints);
            option.Blue.SetControlPoints(splines[3].OriginalPoints);
            return option;
        }

        public class CurvesAction : IQueueAction
        {
            private Point Location = new Point();

            public CurveControl Parent = null;
      
            private CurvePointAction _actionType = CurvePointAction.Add;

            private Spline spline;

            private bool UI_Updated = false;
        
            public CurvesAction(CurveControl parent, Point loc, CurvePointAction actTy)
            {
                Parent = parent;
                Location = loc;
                _actionType = actTy;
                Timestamp = DateTime.Now.Ticks;
                Timeout = 3000;
            }

            public long Timestamp
            {
                set;
                get;
            }

            public int Timeout
            {
                set;
                get;
            }

            public void OnPrepared()
            {
                spline = Parent.TheSpline;
               
            }

            public void Execute()
            {
                switch (_actionType)
                {
                    case CurvePointAction.None:                       
                        if (spline.FocusIndex >= 0)
                        {
                            UI_Updated = true;
                            spline.FocusIndex = -1;
                        }                       
                        break;
                    case CurvePointAction.Clear:
                        UI_Updated = true;
                        spline.Clear();
                        break;
                    case CurvePointAction.Add:
                        UI_Updated = true;
                        spline.AddControlPoint(Location);
                        spline.CalculateCurvePoints();
                        break;
                    case CurvePointAction.Remove:
                        if (spline.FocusIndex >= 0)
                        {
                            UI_Updated = true;
                            spline.RemoveControlPoint();
                            if (spline.OriginalPoints.Count > 0)
                            {
                                spline.CalculateCurvePoints();
                            }                            
                        }                     
                        break;
                    case CurvePointAction.Update:
                        {
                            UI_Updated = true;
                            spline.SetControlPoint(Location);
                            spline.CalculateCurvePoints();
                        }
                        break;                 
                    default:
                        break;
                }         
            }

            public void Simulate()
            {

            }

            public void UpdateUI()
            {
                if (UI_Updated)
                {
                    Parent.Invalidate();
                    Parent.OnCurveUpdated();
                }
            }
        }

    }
}
